#include <QikListBoxModel.h>
#include <QikListBox.h>
#include <MQikListBoxData.h>
#include <QikListBoxData.h>
#include <QikContent.h>
#include <QikZoomDlg.h>
#include <QikCommand.h>

#include "PinQPacketsView.h"
#include "PinQDocument.h"
#include "PinQTask.h"
#include "PinQExternalInterface.h"
#include "PinQ.hrh"
#include <PinQ.rsg>
#include <PinQ.mbg>

CPinQPacketsView* CPinQPacketsView::NewLC(CQikAppUi& aAppUi,
		const TVwsViewId aParentViewId)
	{
	CPinQPacketsView* self = new (ELeave) CPinQPacketsView(aAppUi,aParentViewId);
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

CPinQPacketsView::CPinQPacketsView(CQikAppUi& aAppUi,
		const TVwsViewId aParentViewId) :
	CQikViewBase(aAppUi, aParentViewId)
	{
	}

CPinQPacketsView::~CPinQPacketsView()
	{
	}

void CPinQPacketsView::ConstructL()
	{
	BaseConstructL();
	}

TVwsViewId CPinQPacketsView::ViewId() const
	{
	return TVwsViewId(KUidPinQApp, KUidPinQPacketsView);
	}

void CPinQPacketsView::HandleCommandL(CQikCommand& aCommand)
	{
	TVwsViewId listView;
	switch (aCommand.Type())
		{
		case EQikCommandTypeCancel:
		case EQikCommandTypeDone:
			listView = TVwsViewId(KUidPinQApp, KUidPinQListView);
			iQikAppUi.ActivateViewL(listView);

			RequestFocusL(NULL);
			return;
		case EQikCommandTypeScreen:
			switch (aCommand.Id())
				{
				case EQikCmdGoBack:
					listView = TVwsViewId(KUidPinQApp, KUidPinQListView);
					iQikAppUi.ActivateViewL(listView);

					RequestFocusL(NULL);
					return;
				case EPinQZoomCmd:
					{
					CPinQDocument* document =
							static_cast<CPinQDocument*>(iQikAppUi.Document());
					const TInt zoomFactor =
							CQikZoomDialog::RunDlgLD(document->Preferences().ListViewZoomState());

					if (document->Preferences().SetListViewZoomState(zoomFactor))
						{
						SetZoomFactorL(zoomFactor);
						}
					return;
					}
				}
		}
	CQikViewBase::HandleCommandL(aCommand);

	}

void CPinQPacketsView::ViewConstructL()
	{
	ViewConstructFromResourceL(R_PINQ_PACKETS_CONFIGURATIONS);

	CPinQDocument* document = static_cast<CPinQDocument*>(iQikAppUi.Document());
	SetZoomFactorL(document->Preferences().ListViewZoomState());
	}

_LIT(KDns0Fmt, "Dns req");
_LIT(KNoDnsFmt, "No dns req");
_LIT(KDnsFmt, "Dns req: %ds");
_LIT(KDnsTOFmt, "Dns req: t/o");
_LIT(KDnsErrFmt, "Dns req: %d");
_LIT(KPacketSntFmt, "%d");
_LIT(KPacketOkFmt, "%d %d.%03ds");
_LIT(KPacketSeqFmt, "%d-%d %d.%03ds");
_LIT(KPacketTOFmt, "%d t/o");

void CPinQPacketsView::ViewActivatedL(const TVwsViewId& aPrevViewId,
		const TUid aCustomMessageId, const TDesC8& aCustomMessage)
	{
	//ensure called in right way
	ASSERT(aPrevViewId.iAppUid == KUidPinQApp);ASSERT(aCustomMessageId == KUidPinQDnlItem);
	//unpack input data
	TPinQDnlItemBuf itemBuf;
	itemBuf.Copy(aCustomMessage);
	iCurrentTaskUid = itemBuf().iUid;
	const CPinQTask& task=PinQModel().Task(iCurrentTaskUid);
	//start work with listbox
	CQikListBox* listBox =
			LocateControlByUniqueHandle<CQikListBox>(EPinQPacketsViewListCtrl);

	MQikListBoxModel& model(listBox->Model());
	//remove data from previous activation
	listBox->RemoveAllItemsL();
	if (task.State()==CPinQTask::EStopped && task.PacketsCount()==0)
		return;
	//add packetst from task
	model.ModelBeginUpdateLC();
	TBuf<256> buf;
	if (task.DnsTime()>0)
		buf.Format(KDnsFmt, task.DnsTime());
	else
		switch (task.Error())
			{
			case CPinQTask::ETimeout:
				ASSERT(task.State()!=CPinQTask::EStopped);
				buf.Format(KDnsTOFmt);
				break;
			case CPinQTask::ESystemError:
				buf.Format(KDnsErrFmt, task.SysError());
				break;
			default:
				// migth be later error				ASSERT(aTask.Error()==CPinQTask::ENoError);
				if (task.LastPacket())
					buf.Format(KNoDnsFmt);
				else
					buf.Format(KDns0Fmt);
			}
	MQikListBoxData* listBoxData =
			model.NewDataL(MQikListBoxModel::EDataNormal);
	CleanupClosePushL(*listBoxData);
	listBoxData->AddTextL(buf, EQikListBoxSlotText1);
	CleanupStack::PopAndDestroy(listBoxData);
	for (CPinQTask::TPacket* p=task.FirstPacket(); p; p=p->iNext)
		{
		listBoxData = model.NewDataL(MQikListBoxModel::EDataNormal);
		CleanupClosePushL(*listBoxData);
		if ((p==task.LastPacket())&& (p->iTime==0))
			buf.Format(KPacketSntFmt, p->iSeq);
		else
			{
			if (p->iError==CPinQTask::ETimeout)
				buf.Format(KPacketTOFmt, p->iSeq);
			else
				{
				if (p->iError==CPinQTask::ESeq)
					buf.Format(KPacketSeqFmt, p->iSeq, p->iReceSeq, p->iTime
							/1000);
				else
					buf.Format(KPacketOkFmt, p->iSeq, p->iTime/1000, p->iTime
							% 1000);
				}
			}
		listBoxData->AddTextL(buf, EQikListBoxSlotText1);
		CleanupStack::PopAndDestroy(listBoxData);
		}
	model.ModelEndUpdateL();
	if (model.Count())
		listBox->SetCurrentItemIndexL(model.Count()-1, ETrue, EDrawNow);
	}

enum TRowAct
	{ESkip,EAdd,EReplace};
void CPinQPacketsView::TaskStateChangedL(const CPinQTask& aTask,
		CPinQTask::TState aNewState)
	{
	ASSERT(iCurrentTaskUid==aTask.Uid());
	CPinQTask::TPacket* last=aTask.LastPacket();
	CQikListBox* listBox =
			LocateControlByUniqueHandle<CQikListBox>(EPinQPacketsViewListCtrl);
	MQikListBoxModel& model(listBox->Model());

	TRowAct ra;
	TBuf<256> buf;
	switch (aNewState)
		{
		case CPinQTask::ELookingUp:
			buf.Format(KDns0Fmt);
			ASSERT(model.Count()<2);
			ra=(model.Count()==0) ? EAdd : EReplace;
			break;
		case CPinQTask::EOpenning:
			if (aTask.DnsTime()>0)
				buf.Format(KDnsFmt, aTask.DnsTime());
			else
				buf.Format(KNoDnsFmt);
			ra=(model.Count()==0) ? EAdd : EReplace;
			break;
		case CPinQTask::ESending:
			ASSERT(last);
			buf.Format(KPacketSntFmt, last->iSeq);
			ra=EAdd;
			break;
		case CPinQTask::EStopped:
			if (aTask.State()==CPinQTask::ELookingUp)
				{
				ASSERT(model.Count()<2);
				if (aTask.DnsTime()>0)
					buf.Format(KDnsFmt, aTask.DnsTime());
				else
					{
					switch (aTask.Error())
						{
						case CPinQTask::ETimeout:
							ASSERT(aTask.State()!=CPinQTask::EStopped);
							buf.Format(KDnsTOFmt);
							break;
						case CPinQTask::ESystemError:
							buf.Format(KDnsErrFmt, aTask.SysError());
							break;
						default:
							ASSERT(aTask.Error()==CPinQTask::ENoError);
							buf.Format(KNoDnsFmt);
						}
					}
				ra=(model.Count()==0) ? EAdd : EReplace;
				}
			else
				ra=ESkip;
			break;
		case CPinQTask::ESent:
		case CPinQTask::EReceiving:
		case CPinQTask::EDelay:
			ra=ESkip;
			break;
		case CPinQTask::EReceived:
			ASSERT(last);
			if (last->iError==CPinQTask::ETimeout)
				buf.Format(KPacketTOFmt, last->iSeq);
			else
				{
				if (last->iError==CPinQTask::ESeq)
					buf.Format(KPacketSeqFmt, last->iSeq, last->iReceSeq,
							last->iTime /1000);
				else
					buf.Format(KPacketOkFmt, last->iSeq, last->iTime /1000,
							last->iTime % 1000);
				}
			ra=EReplace;
			break;
		}

	if (ra!=ESkip)
		{
		model.ModelBeginUpdateLC();

		if (ra==EAdd)
			{
			if (last)
				{
				ASSERT(model.Count()>0);//Dns row always 0 because of DNS row
				TInt a=model.Count();
				TUint b=aTask.PacketsCount();
				TUint c=aTask.Pref().PktCount();
				if (aTask.Pref().Loop() && ((aTask.Pref().PktCount()+1)<=model.Count()))
					{
					model.RemoveDataL(1); //PacketsCount >0 because last!=NULL
					ASSERT(aTask.Pref().PktCount()==model.Count());
					}
				}
			MQikListBoxData* listBoxData =
					model.NewDataL(MQikListBoxModel::EDataNormal);
			CleanupClosePushL(*listBoxData);
			listBoxData->AddTextL(buf, EQikListBoxSlotText1);
			CleanupStack::PopAndDestroy(listBoxData);
			}
		else
			{
			TUint index=model.Count()-1;
			ASSERT(index>=0);
			MQikListBoxData* ListBoxData = model.RetrieveDataL(index);
			CleanupClosePushL(*ListBoxData);
			ListBoxData->SetTextL(buf, EQikListBoxSlotText1);
			CleanupStack::PopAndDestroy(ListBoxData);
			model.DataUpdatedL(index);
			}

		model.ModelEndUpdateL();
		if (aNewState==CPinQTask::ESending)
			if (model.Count())
				listBox->SetCurrentItemIndexL(model.Count()-1, ETrue, EDrawNow);
		}
	}

void CPinQPacketsView::SetZoomFactorL(TInt aZoomLevel)
	{
	const TInt zoomFactor = CQikAppUi::ZoomFactorL(aZoomLevel, *iEikonEnv);
	CQikViewBase::SetZoomFactorL(zoomFactor);
	}

// vim: ts=2:sw=2
